﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using System.Windows.Media.Imaging;
using System.Windows.Data;

namespace Odyssey.Controls
{
    /// <summary>
    /// Abstract PageAnimation to create transitons based on a snapshot image of the previous page and a snapshot image of the current page.
    /// </summary>
    public abstract class PageTransitionAnimation : PageAnimation
    {
        private Image image;
        private Image parentImage;
        private Popup popup;

        /// <summary>
        /// Gets or sets the easing function for all timelines in the storyboard.
        /// </summary>
        public IEasingFunction EasingFunction
        {
            get { return (IEasingFunction)GetValue(EasingFunctionProperty); }
            set { SetValue(EasingFunctionProperty, value); }
        }

        /// <summary>
        /// Gets or sets the easing function for all timelines in the storyboard.
        /// </summary>
        public static readonly DependencyProperty EasingFunctionProperty =
            DependencyProperty.Register("EasingFunction", typeof(IEasingFunction), typeof(ScaleAnimation), new PropertyMetadata(null));


        /// <summary>
        /// Gets the default easing function if EasingFunction property is left empty.
        /// </summary>
        protected IEasingFunction GetDefaultEasingFunction()
        {
            return new ExponentialEase { Exponent = 4.0, EasingMode = System.Windows.Media.Animation.EasingMode.EaseOut };
        }

        protected override bool ShowOverride(Page page)
        {
            page.Loaded += new RoutedEventHandler(OnPageLoaded);

            Brush background = page.Resources["PhoneBackgroundBrush"] as Brush;
            image = new Image { Stretch = System.Windows.Media.Stretch.None };
            Canvas cv = new Canvas();
            cv.SetBinding(FrameworkElement.WidthProperty, new Binding { Source = page, Path = new PropertyPath("ActualWidth") });
            cv.SetBinding(FrameworkElement.HeightProperty, new Binding { Source = page, Path = new PropertyPath("ActualHeight") });

            Storyboard sb = GetClearStoryboard();

            var ease = EasingFunction ?? GetDefaultEasingFunction();
            parentImage = PageTransitionService.PageImage;
            Grid parentImageContainer = new Grid { Background = background };
            if (parentImage != null)
            {
                parentImageContainer.Children.Add(parentImage);
                cv.Children.Add(parentImageContainer);
            }

            Grid pageImageContainer = new Grid { Background = background };
            Popup popup = new Popup { Child = cv };
            cv.Children.Add(pageImageContainer);
            pageImageContainer.Children.Add(image);
            PrepareShowAnimation(parentImageContainer, pageImageContainer, ease);

            popup.IsOpen = true;
            sb.Completed += (ss, ee) =>
            {
                popup.IsOpen = false;
                parentImageContainer.Children.Clear();
                cv.Children.Clear();
                image = null;
            };
            sb.Begin();
            sb.Pause();
            return true;
        }

        protected override bool HideOverride(Page page)
        {
            WriteableBitmap bm = new WriteableBitmap(page, null);

            Brush background = page.Resources["PhoneBackgroundBrush"] as Brush;
            image = new Image { Source = bm, Stretch = System.Windows.Media.Stretch.None };
            Canvas cv = new Canvas();
            cv.SetBinding(FrameworkElement.WidthProperty, new Binding { Source = page, Path = new PropertyPath("ActualWidth") });
            cv.SetBinding(FrameworkElement.HeightProperty, new Binding { Source = page, Path = new PropertyPath("ActualHeight") });
            Storyboard sb = GetClearStoryboard();

            IEasingFunction ease = EasingFunction ?? GetDefaultEasingFunction();

            Grid parentPageImageContainer = new Grid { Background = background };
            if (parentImage == null) parentImage = PageTransitionService.PageImage;
            PageTransitionService.PageImage = null;
            if (parentImage != null)
            {
                parentPageImageContainer.Children.Add(parentImage);
                cv.Children.Add(parentPageImageContainer);
            }

            Grid pageImageContainer = new Grid { Background = background };
            pageImageContainer.RenderTransform = new TranslateTransform { Y = 0.0 };

            pageImageContainer.Children.Add(image);
            cv.Children.Add(pageImageContainer);

            Popup popup = new Popup { Child = cv };
            PrepareHideAnimation(parentPageImageContainer, pageImageContainer, ease);

            popup.IsOpen = true;
            this.popup = popup;
            sb.Begin();
            return true;
        }

        public override void OnNavigated(Page page)
        {
            if (popup != null)
            {
                popup.IsOpen = false;
                popup = null;
            }
            base.OnNavigated(page);
        }

        protected abstract void PrepareHideAnimation(Panel parentPageImageContainer, Panel pageImageContainer, IEasingFunction ease);

        protected abstract void PrepareShowAnimation(Panel parentImageContainer, Panel pageImageContainer, IEasingFunction ease);

        private void OnPageLoaded(object sender, RoutedEventArgs e)
        {
            Page page = sender as Page;
            page.Loaded -= OnPageLoaded;
            WriteableBitmap bm = new WriteableBitmap(page, null);
            image.Source = bm;
            image = null;
            OnPageLoaded(page);

            //note: beginning the storyboard when the page is loaded minimizes the delay that occurs while the page is prepared:
            InternalStoryboard.Resume();
        }

        protected virtual void OnPageLoaded(System.Windows.Controls.Page page)
        {
        }
    }
}
